<?php

/* /app/View/Helper/LinkHelper.php */
//App::uses('AppHelper', 'view/helper');

class CombinatorHelper extends AppHelper
{
    public $Vue = null;
    public $libs = array('js' => array(), 'css' => array());
    public $viewLibs = array('js' => array(), 'css' => array());
    public $inline_code = array('js' => array(), 'css' => array());
    public $basePath = null;
    public $cachePath = null;
    public $extraPath = null;

    // default conf
    private $__options = array(
                            'js' => array(
                                'path' => '/js',
                                'cachePath' => '/cache-js',
                                'enableCompression' => true,
                            ),
                            'css' => array(
                                'path' => '/css',
                                'cachePath' => '/cache-css',
                                'enableCompression' => true,
                            ),
                        );

    public function __construct($View, $options = array())
    {
        parent::__construct($View, $options);
        $this->__options['js'] = !empty($options['js']) ? am($this->__options['js'], $options['js']) : $this->__options['js'];

        $this->__options['js'] = !empty($options['js']) ? am($this->__options['js'], $options['js']) : $this->__options['js'];
        $this->__options['css'] = !empty($options['css']) ? am($this->__options['css'], $options['css']) : $this->__options['css'];
        $this->Vue = ClassRegistry::getObject('view');

        $this->__options['js']['path'] = $this->clean_path($this->__options['js']['path']);
        $this->__options['js']['cachePath'] = $this->clean_path($this->__options['js']['cachePath']);
        $this->__options['css']['path'] = $this->clean_path($this->__options['css']['path']);
        $this->__options['css']['cachePath'] = $this->clean_path($this->__options['css']['cachePath']);

        $this->basePath['js'] = WWW_ROOT.COMBINATOR_PATH.$this->__options['js']['path'];
        $this->cachePath['js'] = WWW_ROOT.COMBINATOR_PATH.$this->__options['js']['cachePath'];
        $this->basePath['css'] = WWW_ROOT.COMBINATOR_PATH.$this->__options['css']['path'];
        $this->cachePath['css'] = WWW_ROOT.COMBINATOR_PATH.$this->__options['css']['cachePath'];
        if (Configure::read('App.baseUrl')) {
            $this->extraPath = 'app/webroot/'; // URL Rewrites are switched off, so wee need to add this extra path.
        } else {
            $this->extraPath = ''; // .htaccess files will take care of everything
        }
    }

    public function scripts($type, $async = false)
    {
        switch ($type) {
            case 'js':
                $this->libs[$type] = array_merge($this->libs[$type], $this->viewLibs[$type]);
                $cachefile_js = $this->generate_filename('js');

                return $this->get_js_html($cachefile_js, $async);
            case 'css':
                $this->libs[$type] = array_merge($this->libs[$type], $this->viewLibs[$type]);
                $cachefile_css = $this->generate_filename('css');

                return $this->get_css_html($cachefile_css);
            default:
                $this->libs['js'] = array_merge($this->libs['js'], $this->viewLibs['js']);
                $cachefile_js = $this->generate_filename('js');
                $output_js = $this->get_js_html($cachefile_js, $async);
                $this->libs[$type] = array_merge($this->libs[$type], $this->viewLibs[$type]);
                $cachefile_css = $this->generate_filename('css');
                $output_css = $this->get_css_html($cachefile_css);

                return $output_css."\n".$cachefile_js;
        }
    }

    private function generate_filename($type)
    {
        $this->libs[$type] = array_unique($this->libs[$type]);

        // Create cache folder if not exist
        if (!file_exists($this->cachePath[$type])) {
            mkdir($this->cachePath[$type]);
        }

        // Define last modified to refresh cache if needed
        $lastmodified = 0;
        foreach ($this->libs[$type] as $key => $lib) {
            $lib = $this->clean_lib_list($lib, $type);
            if (file_exists($this->basePath[$type].'/'.$lib)) {
                $lastmodified = max($lastmodified, filemtime($this->basePath[$type].'/'.$lib));
            }
            $this->libs[$type][$key] = $lib;
        }
        $hash = $lastmodified.'-'.md5(serialize($this->libs[$type]).'_'.serialize($this->inline_code[$type]));

        return 'cache-'.$hash.'.'.$type;
    }

    private function get_js_html($cachefile, $async)
    {
        if (false === file_exists($this->cachePath['js'].'/'.$cachefile)) {
            // Get the content
            $file_content = '';
            foreach ($this->libs['js'] as $lib) {
                $change = strstr($lib, 'http://');
                if ($change != '') {
                    $lib = str_replace('.js', '', $lib);
                    $file_content .= "\n\n".file_get_contents($lib);
                } else {
                    $file_content .= "\n\n".file_get_contents($this->basePath['js'].'/'.$lib);
                }
            }
            // If compression is enable, compress it !
            if ($this->__options['js']['enableCompression']) {
                App::import('Vendor', 'jsmin');
                $file_content = trim(JSMin::minify($file_content));
            }

            // Get inline code if exist
            // Do it after jsmin to preserve variable's names
            if (!empty($this->inline_code['js'])) {
                foreach ($this->inline_code['js'] as $inlineJs) {
                    $file_content .= "\n\n".$inlineJs;
                }
            }
            if ($fp = fopen($this->cachePath['js'].'/'.$cachefile, 'wb')) {
                fwrite($fp, $file_content);
                fclose($fp);
            }
        }
        if (COMBINATOR_PATH != 'admin/') {
            return '<script '.($async == true ? 'async ' : '').'src="'.$this->root_url('/'.COMBINATOR_PATH.$this->__options['js']['cachePath'].'/'.$cachefile).'" type="text/javascript"></script>';
        } else {
            return '<script '.($async == true ? 'async ' : '').'src="'.$this->url('/'.$this->extraPath.$this->__options['js']['cachePath'].'/'.$cachefile).'" type="text/javascript"></script>';
        }
    }

    private function get_css_html($cachefile)
    {
        if (false === file_exists($this->cachePath['css'].'/'.$cachefile)) {
            // Get the content
            $file_content = '';
            foreach ($this->libs['css'] as $lib) {
                $change = strstr($lib, 'http://');
                if ($change != '') {
                    $lib = str_replace('.css', '', $lib);
                    $file_content .= "\n\n".file_get_contents($lib);
                } else {
                    $file_content .= "\n\n".file_get_contents($this->basePath['css'].'/'.$lib);
                }
            }
            // Get inline code if exist
            if (!empty($this->inline_code['css'])) {
                foreach ($this->inline_code['css'] as $inlineCss) {
                    $file_content .= "\n\n".$inlineCss;
                }
            }

            // If compression is enable, compress it !
            if ($this->__options['css']['enableCompression']) {
                App::import('Vendor', 'cssmin', array('file' => 'cssmin'.DS.'cssmin.php'));
                $css_minifier = new CssMinifier($file_content); // JossToDo - here we could implement filters and plugins, as per http://code.google.com/p/cssmin/wiki/Configuration
                $file_content = $css_minifier->getMinified();
            }

            if ($fp = fopen($this->cachePath['css'].'/'.$cachefile, 'wb')) {
                fwrite($fp, $file_content);
                fclose($fp);
            }
        }
        if (COMBINATOR_PATH != 'admin/') {
            return '<link href="'.$this->root_url('/'.COMBINATOR_PATH.$this->__options['css']['cachePath'].'/'.$cachefile).'" rel="stylesheet" type="text/css" >';
        } else {
            return '<link href="'.$this->url('/'.$this->extraPath.$this->__options['css']['cachePath'].'/'.$cachefile).'" rel="stylesheet" type="text/css" >';
        }
    }

    public function add_libs($type, $libs, $toEnd = false)
    {
        switch ($type) {
            case 'js':
            case 'css':
                if (is_array($libs)) {
                    foreach ($libs as $lib) {
                        if ($toEnd) {
                            $this->viewLibs[$type][] = $lib;
                        } else {
                            $this->libs[$type][] = $lib;
                        }
                    }
                } else {
                    if ($toEnd) {
                        $this->viewLibs[$type][] = $libs;
                    } else {
                        $this->libs[$type][] = $libs;
                    }
                }
                break;
        }
    }

    public function reset_lib_list($type)
    {
        switch ($type) {
            case 'js':
            case 'css':
                $this->libs[$type] = array();
                break;
        }
    }

    public function add_inline_code($type, $codes)
    {
        switch ($type) {
            case 'js':
            case 'css':
                if (is_array($codes)) {
                    foreach ($codes as $code) {
                        $this->inline_code[$type][] = $code;
                    }
                } else {
                    $this->inline_code[$type][] = $codes;
                }
                break;
        }
    }

    private function clean_lib_list($filename, $type)
    {
        if (strpos($filename, '?') === false) {
            if (strpos($filename, '.'.$type) === false) {
                $filename .= '.'.$type;
            }
        }

        return $filename;
    }

    private function clean_path($path)
    {
        // delete the / at the end of the path
        $len = strlen($path);
        if (strrpos($path, '/') == ($len - 1)) {
            $path = substr($path, 0, $len - 1);
        }

        // delete the / at the start of the path
        if (strpos($path, '/') == '0') {
            $path = substr($path, 1, $len);
        }

        return $path;
    }
}
